void CDicomBMPDlg::ConvertDicomToBMP()
{

 short int nCols = 0, nRows = 0;
    short int nBitsAllocated, nSamplesPerPixel = 1;
 short int nHighBit = 0;
 float fWindowWidth = 0, fWindowCenter = 0 , fRescaleSlope = 1, fRescaleIntercept = 0;
 BOOL bIsSigned = FALSE;

 BOOL bGroup2Done = FALSE, bGroup28Done = FALSE, bPixelDataDone = FALSE;

 int nBytesP = 0;
 int nFrameSize = 0;
 long int nLength;
 const char *pszFileName = m_strFileName.GetBuffer(3);
 char szPhotometric[32]="", szTemp[32]="", szTransferSyntaxUID[80]="";

 BOOL bImplicitVR = TRUE;
 COMPRESSION_MODE nCompressionMode = COMPRESS_NONE;
 DATA_ENDIAN nDataEndian = LITTLE_ENDIAN;
 int i;
 int nBytes;


   FILE *fp;
   char *pData = 0;
   short int gTag, eTag;
   int nNumFrames = 1;

   fp = fopen(pszFileName, "rb");
   if (!fp)
    {
       AfxMessageBox("Failed to open file for read.");
       return;
    }

    while(fread(&gTag, sizeof(short), 1, fp) == 1)
    {
    if (nDataEndian == BIG_ENDIAN)
   SwapWord((char *) &gTag, 1);

      switch(gTag)
      {
    case 0x0002: // Meta header.

   if (bGroup2Done)
      break;

   fread(&eTag, sizeof(short), 1, fp);
   // Meta header is always in Little Endian Explicit VR syntax.
         switch(eTag)
          {
             case 0x0010: // Transfer syntax UID
     if (readString(fp, szTransferSyntaxUID, FALSE, LITTLE_ENDIAN) != 0)
      break;

    // Check data endian.
    if (!strcmp(szTransferSyntaxUID, "1.2.840.10008.1.2.2")) // Explicit VR Big Endian 
     nDataEndian = BIG_ENDIAN; // Big Endian
    else
     nDataEndian = LITTLE_ENDIAN; // Little Endian

    // Check if it is implicit VR or Explicit VR
    if (!strcmp(szTransferSyntaxUID, "1.2.840.10008.1.2")) // Implicit VR Little Endian 
     bImplicitVR = TRUE; // Implicit VR
    else
     bImplicitVR = FALSE; // Explicit VR

    // Parse the encapsulation/compression
    if (!strcmp(szTransferSyntaxUID, "1.2.840.10008.1.2.4.50")) // JPEG lossy
     nCompressionMode = COMPRESS_JPEGLOSSY;
    else if (!strcmp(szTransferSyntaxUID, "1.2.840.10008.1.2.4.51")) // JPEG lossy 12bit
     nCompressionMode = COMPRESS_JPEGLOSSY12BIT;
    else if (!strcmp(szTransferSyntaxUID, "1.2.840.10008.1.2.4.70")) // JPEG lossless first order prediction
     nCompressionMode = COMPRESS_JPEGLOSSLESS;
    else if (!strcmp(szTransferSyntaxUID, "1.2.840.10008.1.2.4.57")) // JPEG lossless process 14
     nCompressionMode = COMPRESS_JPEGLOSSLESS2;
    else if (!strcmp(szTransferSyntaxUID, "1.2.840.10008.1.2.5")) // RLE
     nCompressionMode = COMPRESS_RLE;

    bGroup2Done = TRUE;

   break;

   }
   break;

       case 0x0008: // First non-Meta group
         fread(&eTag, sizeof(short), 1, fp);
       if (nDataEndian == BIG_ENDIAN)
      SwapWord((char *) &eTag, 1);

   if ((eTag == 0x0005) || (eTag == 0x0008))
    bGroup2Done = TRUE;
   break;

       case 0x0028: // Image pixel data info group
         fread(&eTag, sizeof(short), 1, fp);

   if (bGroup28Done)
      break;

       if (nDataEndian == BIG_ENDIAN)
      SwapWord((char *) &eTag, 1);

         switch(eTag)
          {
            case 0x0002: // Samples per Pixel
    nSamplesPerPixel = readUS(fp, nDataEndian);
               break;

            case 0x0004:  // Photometric Interpolation
    readString(fp, szPhotometric, bImplicitVR, nDataEndian);
               break;

            case 0x0008:  // Number of frames
    nNumFrames = readIS(fp, bImplicitVR, nDataEndian);
               break;

             case 0x0010: // Rows
      nRows = readUS(fp, nDataEndian);
               break;

            case 0x0011: // Columns
      nCols = readUS(fp, nDataEndian);
               break;

            case 0x0100: // Bits allocated
      nBitsAllocated = readUS(fp, nDataEndian);
               break;

   case 0x0102: // High bit
    nHighBit = readUS(fp, nDataEndian);
    break;

   case 0x0103: // Is signed?
    bIsSigned = readUS(fp, nDataEndian);
    break;

   case 0x1050: // Window Center
    fWindowCenter = readDS(fp, bImplicitVR, nDataEndian);
    break;

   case 0x1051: // Window Width
    fWindowWidth = readDS(fp, bImplicitVR, nDataEndian);
    break;

   case 0x1052: // Rescale intercept
    fRescaleIntercept = readDS(fp, bImplicitVR, nDataEndian);
    break;

   case 0x1053: // Rescale slope
    fRescaleSlope = readDS(fp, bImplicitVR, nDataEndian);
    bGroup28Done = TRUE;
    break;

   default:
    // do nothing
    break;
           }
         break;
        case 0x7fe0:
         fread(&eTag, sizeof(short), 1, fp);
   if (bPixelDataDone)
    break;

       if (nDataEndian == BIG_ENDIAN)
      SwapWord((char *) &eTag, 1);

         if (eTag == 0x0010)
         {
    nBytesP = nSamplesPerPixel*nBitsAllocated/8;
    nFrameSize = nCols * nRows * nBytesP;
    nLength = nNumFrames * nFrameSize;

    // Don't try to parse grup 2 and group 28 any more
    bGroup2Done = TRUE;
    bGroup28Done = TRUE;

    // Parse pixel data
    switch(nCompressionMode)
    {
    case COMPRESS_NONE:
     pData = new char[nLength + 16];
     fseek(fp, 4, SEEK_CUR); // Skip 4 bytes (length bytes)
     nBytes = fread(pData, 1, nLength, fp);

     if (nBytes != nLength)
     {
      AfxMessageBox("Failed to read all pixel data.");
     }
     bPixelDataDone = TRUE;
     break;

    case COMPRESS_RLE:
     AfxMessageBox("RLE compression not supported at this moment");
     // To do:  
     //   1. Read the offset table.
     //   2. Read and uncompress RLE image frames into either RGB or monochrome format.
     //   3. Put frames in the pData buffer, one frame after another.
     //  Public domain RLE decompression source code is in Papyrus and dcmtk. 
     break;
    case COMPRESS_JPEGLOSSY:
     AfxMessageBox("JPEG lossy compression not supported at this moment");
     // To do:  
     //   1. Read the offset table
     //   2. Read and uncompress JPEG image frames into either RGB or monochrome format.
     //   3. Put frames in the pData buffer, one frame after another.
     //  Public domain JPEG decompression source code is in Papyrus and dcmtk. 
     break;
    case COMPRESS_JPEGLOSSY12BIT:
     AfxMessageBox("JPEG lossy 12-bit compression not supported at this moment");
     // To do:  
     //   1. Read the offset table
     //   2. Read and uncompress JPEG image frames into either RGB or monochrome format.
     //   3. Put frames in the pData buffer, one frame after another.
     //  Public domain JPEG decompression source code is in Papyrus and dcmtk. 
     break;
    case COMPRESS_JPEGLOSSLESS:
    case COMPRESS_JPEGLOSSLESS2:
     AfxMessageBox("JPEG lossless compression not supported at this moment");
     // To do:  
     //   1. Read the offset table
     //   2. Read and uncompress JPEG image frames into either RGB or monochrome format.
     //   3. Put frames in the pData buffer, one frame after another.
     //  Public domain JPEG decompression source code is in Papyrus and dcmtk. 
     break;
    }

         }
         break;
   }

   if (pData) 
    break; // We are done.
    }

  fclose(fp);

  if (pData) // Have we got the pixel data?
  {
   // Need to do byte swap?
   if (nDataEndian == BIG_ENDIAN)
   {
    if (nBitsAllocated > 8)
   SwapWord(pData, nLength/2);
   }

   if (nBitsAllocated > 8)
   {
    // We need to convert it to 8-bit.
    char *pNewData;

    pNewData = convertTo8Bit(pData, nLength/2, bIsSigned, nHighBit,
     fRescaleSlope, fRescaleIntercept, fWindowCenter, fWindowWidth);

    // Use the new 8-bit data.
    if (pNewData)
    {
     delete [] pData;
     pData = pNewData;
     nBytesP = 1;
     nFrameSize /= 2;

     nLength /= 2;
    }
   }

   // Write BMP files
   for (i = 0; i < nNumFrames; i++)
  WriteBMPFile(pData + nFrameSize*i, nFrameSize, nCols, nRows, nBytesP, szPhotometric, i+1);

   // Free the memory.
   delete [] pData;

   AfxMessageBox("Images successfully converted into BMP.");

  }

}

 

int CDicomBMPDlg::WriteBMPFile(char *pData, int nFrameSize, short nCols, short nRows, int nBytesP, char *pszPhotometric, int nFrameNum)
{

	 BITMAPFILEHEADER bf;
	 BITMAPINFOHEADER bi;
	 int nPaletteSize = sizeof(RGBQUAD)*256;
	 char szBMPFileName[512], *cc;
	 FILE *fp;
	 int i, j, nBytes, nRowPadding, nRowBytes;
	 unsigned char oneLutSlot[4];
	 char szPadding[4] = {'\0', '\0', '\0', '\0'};

	 if (!strncmp(pszPhotometric, "RGB", 3) || !strncmp(pszPhotometric, "YBR", 3))
	  nPaletteSize = 0;

	 // Attention:
	 //  1. BMP image rows need to be 4-byte aligned.
	 //  2. BMP image is usually bottom up in reverse direction to DICOM images.
	 nRowBytes = nCols*nBytesP;
	 nRowPadding = nRowBytes%4;
 
	 //here fill in the two info structure
	 bf.bfType = 0x4D42; 
	 bf.bfSize= sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + nPaletteSize + nFrameSize + nRowPadding*nRows;
	 bf.bfReserved1 = 0; 
	 bf.bfReserved2 = 0; 
	 bf.bfOffBits=sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + nPaletteSize;

	 bi.biSize=sizeof(BITMAPINFOHEADER);
	 bi.biWidth = nCols; 
	 bi.biHeight = nRows; 
	 bi.biPlanes = 1;
	 if (nPaletteSize == 0)
	 {
	  bi.biBitCount = 24;
	  bi.biClrUsed = 0; 
	  bi.biClrImportant = 0;
	 }
	 else
	 {
	  bi.biBitCount = 8;
	  bi.biClrUsed = 256; 
	  bi.biClrImportant = 256;
	 }
	 bi.biCompression = 0; 
	 bi.biSizeImage = nFrameSize;
 
	  //
	  // Resolutions are in pixels per meter.  Our IMAGES file uses
	  // a resolution of 72 pixels per inch, which when multiplied by
	  // 39.37 inches per meter, gives us 2835 pixels per meter.
	  //
	 bi.biXPelsPerMeter = 2835; 
	 bi.biYPelsPerMeter = 2835;
 
	 // Make file name and give it a .BMP extension.
	 strcpy(szBMPFileName, m_strFileName.GetBuffer(3));

	 if (!(cc = strrchr(szBMPFileName, '.'))) // Find the '.' or end of file name.
	  cc = szBMPFileName + strlen(szBMPFileName);
	 sprintf(cc, "_%04d.BMP", nFrameNum); // Append file number and extension.

	 // Open the file for wirte.
	 fp = fopen(szBMPFileName, "wb");
	 if (fp == NULL)
	  AfxMessageBox("Failed to open file for write.");

	 // Write the BMP and DIB file headers.
	 nBytes = fwrite((void *)&bf, 1, sizeof(BITMAPFILEHEADER), fp);
	 // if (nBytes != sizeof(BITMAPFILEHEADER))
	 //    post your error message here.

	 nBytes = fwrite((void *)&bi, 1, sizeof(BITMAPINFOHEADER), fp);
	 // if (nBytes != sizeof(BITMAPINFOHEADER))
	 //    post your error message here.


	 // Write the color palette if 8-bit
	 if (nPaletteSize != 0)
	  for (i = 0; i < 256; i++)
	  {
	   oneLutSlot[0] = oneLutSlot[1] = oneLutSlot[2] = i; // Grayscale LUT.
	   oneLutSlot[3] = 0;
	   fwrite(oneLutSlot, 1, 4, fp); // Write one color palette slot.
	  }

	 // Now write the actual pixel data.
	 cc = pData + (nRows - 1)*nRowBytes;
	 if (nPaletteSize != 0) // Grayscale
	  for (i = 0; i < nRows; i ++)
	  {
	   nBytes = fwrite(cc, 1, nRowBytes, fp); // Write a row.
	   //if (nBytes != nRowBytes)
	   //    post your error message here.

	   if (nRowPadding) // Pad the row.
		fwrite(szPadding, 1, nRowPadding, fp);

	   cc -= nRowBytes;
	  }
	 else
	  for (i = 0; i < nRows; i ++)
	  {
	   for (j = 0; j < nCols; j++, cc += 3)
	   {
		fputc(*(cc + 2), fp); // B
		fputc(*(cc + 1), fp); // G
		fputc(*cc, fp);       // R
	   }

	   if (nRowPadding) // Pad the row.
		fwrite(szPadding, 1, nRowPadding, fp);

	   cc -= 2*nRowBytes;
	  }
  
	 fclose(fp);

	 return 0;
}